/**
 * @use(qx.module.Manipulating)
 * @use(qx.module.Attribute)
 * @use(qx.module.Event)
 * @use(qx.module.Css)
 * @use(qx.module.Traversing)
 * @use(qx.module.Animation)
 *
 * @use(lastfmbackup.Language)
 * 
 * @asset(lastfmbackup/icon/*)
 * 
 * @ignore(unsafeWindow.*)
 */
qx.Class.define("lastfmbackup.Application", {
  
  extend  : qx.application.Native,
  include : qx.locale.MTranslation,

  properties : {
    
    status : {
      check : "String",
      init  : "",
      event : "changeStatus"
    }
    
  },
  
  members : {
    
    _layout  : null,
    _model   : null,
    _tracker : null,
    
    
    _createModel : function(username)
    {
      this._model = new lastfmbackup.model.Sync();
      this._model.setFetchModel(new lastfmbackup.model.RecentTracks(username));
      this._model.setStorageModel(new lastfmbackup.model.Storage(username));
      
      this._model.addListener("prepared", function(event)
      {
        var awaiting = event.getData();
        if(awaiting)
        {
          var formatter = new qx.util.format.NumberFormat();
          formatter.setMaximumFractionDigits(0);
          
          this.setStatus(this.tr("%1 scrobbles awaiting", formatter.format(awaiting)));
          this._layout.getProgressButtons().show("run");
        }
        else
        {
          this.setStatus(this.tr("Backup is in sync"));
        }
      }, this);
      this._model.addListener("complete", function(event)
      {
        this.setStatus("Backup completed");
        this._layout.getProgressButtons().hide("abort");
      }, this);
      this._model.addListener("abort", function(event)
      {
        this.setStatus(this.tr("Aborted"));
        this._layout.getProgressButtons().hide("abort");
        this._layout.getProgressButtons().show("run");
      }, this);
    },
    
    _save : function(blob, filename)
    {
      var anchor = q.create("<a/>")
        .setAttribute("download", filename) // since FireFox 20
        .setAttribute("href",     window.URL.createObjectURL(blob));
      
      var event  = document.createEvent("MouseEvents");
      event.initEvent("click", true, true);
      anchor[0].dispatchEvent(event);
    },
    
    _onStorageExecute : function(event)
    {
      switch(event.getData())
      {
        case "clear":
          if(window.confirm(this.tr("Do you really want to remove the backup data?"))) 
          {
            this._model.getStorageModel().resetData();
            this._model.prepare();
            this.setStatus(this.tr("Preparing.."));
            
            if(this._tracker)
            {
              this._tracker._trackPageview("/userscript/clear");          
            }
          }
          break; 
        case "save-csv":
          this._model.getStorageModel().addListenerOnce("fetch", function(event)
          {
            var blob = event.getData();
            if(blob)
            {
              this._save(blob, "{0}.csv".format(this._model.getStorageModel().getUsername()));
            }
            
            if(this._tracker)
            {
              this._tracker._trackPageview("/userscript/save/csv");          
            }
          }, this);
          this._model.getStorageModel().fetchCsvBlob();
          break; 
        case "save-json":
          this._model.getStorageModel().addListenerOnce("fetch", function(event)
          {
            var blob = event.getData();
            if(blob)
            {
              this._save(blob, "{0}.json".format(this._model.getStorageModel().getUsername()));
            }
            
            if(this._tracker)
            {
              this._tracker._trackPageview("/userscript/save/json");          
            }            
          }, this);
          this._model.getStorageModel().fetchJsonBlob();
          break;
      }
    },
    
    _createStatusTable : function()
    {
      var table = new lastfmbackup.view.StatusTable();
      
      var filterTableStats = function(map)
      {
        return !map ? null : Object.dict(Object.items(map).filter(function(pair)
        {
          return pair[0] in {"lastRun":0, "lastScrobble":0, "scrobbles":0, "storageUsed":0};
        }));
      };
      this._model.getStorageModel().addListener("changeStats", function(event)
      {
        table.set(filterTableStats(event.getData()));
      });
      table.set(filterTableStats(this._model.getStorageModel().getStats()));
      
      var buttons = new lastfmbackup.view.StorageControlBar();
      buttons.addListener("execute", this._onStorageExecute, this);
      
      table.getStorageControlElement().append(buttons.getElement());
      
      return table;
    },
    
    _createProgressBar : function()
    {
      var progressBar = new lastfmbackup.view.ProgressBar();
      
      this._model.bind("progress", progressBar, "progress", {converter : function(value)
      {
        return value ? value : 0;
      }});
      this._model.addListener("changeProgressType", function(event)
      {
        var map = {
          "load" : this.tr("Synchronizing.."),
          "save" : this.tr("Saving..")
        };
        if(event.getData() in map)
        {
          this.setStatus(map[event.getData()]);          
        }
      }, this);
      this.bind("status", progressBar, "status");
      
      return progressBar;
    },
    
    _createProgressButtons : function()
    {
      var buttons = new lastfmbackup.view.ProgressControlBar();
      buttons.addListener("execute", function(event)
      {
        switch(event.getData())
        {
          case "run":
            this._model.run();
            this.setStatus(this.tr("Synchronizing.."));
            buttons.hide("run");
            buttons.show("abort");
            
            if(this._tracker)
            {
              this._tracker._trackPageview("/userscript/run");          
            }
            break; 
          case "abort":
            this._model.abort();
            this.setStatus("Aborting..");
            
            if(this._tracker)
            {
              this._tracker._trackPageview("/userscript/abort");          
            }
            break; 
        }
      }, this);
      
      return buttons;
    },
    
    _createView : function()
    {
      this._layout = new lastfmbackup.view.Layout();
      this._layout.set({
        statusTable     : this._createStatusTable(),
        progressBar     : this._createProgressBar(),
        progressButtons : this._createProgressButtons()
      });
      
      var tab = new lastfmbackup.view.Tab(); 
      tab.addListener("appear", function()
      {
        this._model.prepare();
        this.setStatus(this.tr("Preparing.."));
        
        if(this._tracker)
        {
          this._tracker._trackPageview("/userscript/prepare");          
        }
      }, this);
      tab.getElement().append(this._layout.getElement());
    },
    
    _create : function(global)
    {
      if("LFM" in global)
      {
        var resource = global.LFM.get("ParentResource");
        if(resource.type != 4)
        {
          throw new Error("This isn't a settings page");
        }
        this._createModel(resource.name);
        
        if("_gat" in global)
        {
          this._tracker = global._gat._getTracker(qx.core.Environment.get("lastfmbackup.analyticsId"));
        }
      }
      else if(qx.core.Environment.get("qx.debug"))
      {
        this._createModel("saaj");
      }
      else
      {
        throw new Error("Unsupported startup mode");
      }
      this._createView();
    },
    
    _run : qx.core.Environment.select("engine.name", {

      "webkit" : function()
      {
        if(qx.core.Environment.get("qx.debug"))
        {
          this._create(window);
        }
        else
        {
          // Tampermonkey runs sandboxed whatever @grant is set
          // Propagate global qx for JSONP callbacks
          unsafeWindow.qx = window.qx;
          this._create(unsafeWindow);
        }
      },

      "default" : function()
      {
        // Greasemonkey in `@grant none` mode
        this._create(window);
      }
      
    }),
    
    main : function()
    {
      this.base(arguments);

      if(qx.core.Environment.get("qx.debug"))
      {
        qx.log.appender.Native;
        qx.log.appender.Console;
      }
      
      this._run();
    }
    
  }
  
});